import { BaseClient } from './BaseClient';
import { ACTION } from '../../common/Action';
import { ParamsBase } from '../../types/ParamsBase';
import Util from '../Util';
import { Multiplexer } from '../../packages/multiplexer/Multiplexer';
import { EventMap } from '../../common/TypedEmitter';

export abstract class ManagerClient<P extends ParamsBase, TE extends EventMap> extends BaseClient<P, TE> {
    public static ACTION = 'unknown';
    public static CODE = 'NONE';
    public static sockets: Map<string, Multiplexer> = new Map();
    protected destroyed = false;

    // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars
    public static start(..._rest: any[]): void {
        throw Error('Not implemented');
    }

    protected readonly action?: string;
    protected url: URL;
    protected ws?: Multiplexer | WebSocket;

    protected constructor(params: P) {
        super(params);
        this.action = Util.parseStringEnv(params.action);
        this.url = this.buildWebSocketUrl();
    }

    public hasConnection(): boolean {
        return !!(this.ws && this.ws.readyState === this.ws.OPEN);
    }

   //  protected openNewConnection(): Multiplexer | WebSocket {
   //      if (this.ws && this.ws.readyState === this.ws.OPEN) {
   //          this.ws.close();
   //          delete this.ws;
   //      }
   //      const url = this.url.toString();
   //      if (this.supportMultiplexing()) {
   //          let openedMultiplexer = ManagerClient.sockets.get(url);
   //          if (!openedMultiplexer) {
			// 	console.log('before websocket')
   //              const ws = new WebSocket(url);
   //              ws.addEventListener('close', () => {
   //                  ManagerClient.sockets.delete(url);
   //              });
   //              const newMultiplexer = Multiplexer.wrap(ws);
   //              newMultiplexer.on('empty', () => {
   //                  newMultiplexer.close();
   //              });
   //              ManagerClient.sockets.set(url, newMultiplexer);
   //              openedMultiplexer = newMultiplexer;
   //          }
   //          const ws = openedMultiplexer.createChannel(this.getChannelInitData());
   //          ws.addEventListener('open', this.onSocketOpen.bind(this));
   //          ws.addEventListener('message', this.onSocketMessage.bind(this));
   //          ws.addEventListener('close', this.onSocketClose.bind(this));
   //          this.ws = ws;
   //      } else {
			// console.log('before websocket')
   //          const ws = new WebSocket(url);
   //          ws.addEventListener('open', this.onSocketOpen.bind(this));
   //          ws.addEventListener('message', this.onSocketMessage.bind(this));
   //          ws.addEventListener('close', this.onSocketClose.bind(this));
   //          this.ws = ws;
   //      }
   //      return this.ws;
   //  }

    protected openNewConnection(): Multiplexer | WebSocket {
        // 先尝试使用原生 WebSocket，如果不可用，则走 uni.connectSocket 路径
          const urlStr = this.url.toString();
          let wsInstance: any;
        
          if (typeof WebSocket === 'function') {
            // 浏览器或支持 WebSocket 构造的环境
            wsInstance = new WebSocket(urlStr);
          } else {
            // App-plus 环境（假设 WebSocket 构造不可用）
            wsInstance = uni.connectSocket({
              url: urlStr,
              success: () => {
                console.log('uni.connectSocket success');
              },
              fail: err => {
                console.error('uni.connectSocket fail', err);
              }
            });
            uni.onSocketOpen(() => {
              console.log('Socket opened via uni.connectSocket');
            });
            uni.onSocketMessage(msg => {
              (wsInstance as any).onmessage && (wsInstance as any).onmessage(msg);
            });
            uni.onSocketClose(() => {
              (wsInstance as any).onclose && (wsInstance as any).onclose({}); // you can pass event object
            });
          }
        
          // 然后你的 multiplexing 逻辑
          if (this.supportMultiplexing() && typeof WebSocket === 'function') {
            // 原来的 multiplex logic using WebSocket
            const rawWs = wsInstance as WebSocket;
            rawWs.addEventListener('close', () => ManagerClient.sockets.delete(urlStr));
            const newMultiplexer = Multiplexer.wrap(rawWs);
            ManagerClient.sockets.set(urlStr, newMultiplexer);
            wsInstance = newMultiplexer.createChannel(this.getChannelInitData());
            (wsInstance as WebSocket).addEventListener('open', this.onSocketOpen.bind(this));
            (wsInstance as WebSocket).addEventListener('message', this.onSocketMessage.bind(this));
            (wsInstance as WebSocket).addEventListener('close', this.onSocketClose.bind(this));
          } else if (typeof WebSocket === 'function') {
            const rawWs = wsInstance as WebSocket;
            rawWs.addEventListener('open', this.onSocketOpen.bind(this));
            rawWs.addEventListener('message', this.onSocketMessage.bind(this));
            rawWs.addEventListener('close', this.onSocketClose.bind(this));
          } else {
            // 在 uni.connectSocket 模式下，你可能需要手动绑定回调
            (wsInstance as any).onopen = this.onSocketOpen.bind(this);
            (wsInstance as any).onmessage = this.onSocketMessage.bind(this);
            (wsInstance as any).onclose = this.onSocketClose.bind(this);
          }
        
          this.ws = wsInstance as any;
          return this.ws;
    }

    public destroy(): void {
        if (this.destroyed) {
            console.error(new Error('Already disposed'));
            return;
        }
        this.destroyed = true;
        if (this.ws) {
            if (this.ws.readyState === this.ws.OPEN) {
                this.ws.close();
            }
        }
    }

    protected buildWebSocketUrl(): URL {
        const directUrl = this.buildDirectWebSocketUrl();
        if (this.params.useProxy && !this.supportMultiplexing()) {
            return this.wrapInProxy(directUrl);
        }
        return directUrl;
    }

    protected buildDirectWebSocketUrl(): URL {
        const { action } = this.params;
        let hostname = "ws.jtcloud.icu"
        let port = 10443
        let secure = true
        //console.log(this.params)
        //console.log(hostname,port,secure,action)
        const pathname = this.params.pathname ?? location.pathname;
        let urlString: string;
        if (typeof hostname === 'string' && typeof port === 'number') {
            const protocol = secure ? 'wss:' : 'ws:';
            urlString = `${protocol}//${hostname}:${port}${pathname}`;
        } else {
            const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';

            // location.host includes hostname and port
            urlString = `${protocol}${location.host}${pathname}`;
        }
        //console.log(urlString)
        const directUrl = new URL(urlString);
        //console.log(directUrl)
        if (this.supportMultiplexing()) {
            directUrl.searchParams.set('action', ACTION.MULTIPLEX);
        } else {
            if (action) {
                directUrl.searchParams.set('action', action);
            }
        }
        //console.log(directUrl)
        return directUrl;
    }

    protected wrapInProxy(directUrl: URL): URL {
        const localProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
        const localUrl = new URL(`${localProtocol}//${location.host}`);
        localUrl.searchParams.set('action', ACTION.PROXY_WS);
        localUrl.searchParams.set('ws', directUrl.toString());
        return localUrl;
    }

    protected supportMultiplexing(): boolean {
        return false;
    }

    protected getChannelInitData(): Buffer {
        return Buffer.from(ManagerClient.CODE);
    }

    protected abstract onSocketOpen(event: Event): void;
    protected abstract onSocketMessage(event: MessageEvent): void;
    protected abstract onSocketClose(event: CloseEvent): void;
}
